
fn base(){
    let mut x = 100i32;

    let ref_x: &mut i32 = &mut x;
    *ref_x = 200i32;
    println!("ref_x : {}", ref_x);
}


use std::cell::Cell;
//TODO:  use  name field as copyablePointer -> Cell<CopyablePointer<String>> ;
//  Compile error:  [Box] is not Copyable
#[derive(Debug, Clone, Copy)]
struct Teacher {
    //name: Cell<Box<String>>,
    age: i8,
}
impl Teacher {
    /*
    fn new(name: Box<String>, age: i8) -> Self{
        Teacher { name, age}
    }
    */
    fn new(age: i8) -> Self{
        Teacher {age}
    }
}
struct Class {
    teacher: Cell<Option<Teacher>>,
}
impl Class {
    fn new() -> Self {
        Class {teacher: Cell::new(None)}
    }
    fn set_teacher(&self, teacher: Teacher) {
        self.teacher.set(Some(teacher)); // drop the Old teacher
    }

    fn replace_teacher(&self, teacher: Teacher) -> Option<Teacher> {
        self.teacher.replace(Some(teacher))
    }
    fn take_teacher(&self) -> Option<Teacher> {
        self.teacher.take()
    }

    fn teacher(&self) -> Option<Teacher> {
        self.teacher.get()
    }

}

/*
 * NOTE: 
 *  1. cell is for T  && RefCell is for &T
 *  2. cell is for move in & out in runtime-borrow-check (especially for copyable value)
 *  3. get ==> T must impl trait Copy
 *  4. many mem-operation take placed internally in Cell
 */
fn cell(){
    // only use the  get & set options
    //  NOTE: cell only used with Copyable T 
    //  get:
    //      get-> T, NOTE:  T must impl COPY TRAIT
    //      get_mut() -> &mut T ::==> for  mutable Cell
    //      into_inner() -> Consume the Cell self
    //  set 
    //      set(T) -> NOTE: drop the old T
    //      replace -> don't drop the old T
    //      swap -> don't drop anything
    //      take -> take out T , and then this=Default::default()
    let class = Class::new();
    class.set_teacher(Teacher::new(20));

    assert_eq!(20, class.teacher().unwrap().age);
    assert_eq!(20, class.teacher().unwrap().age);

    assert_eq!(20, class.replace_teacher(Teacher::new(30)).unwrap().age);
    assert_eq!(30, class.teacher().unwrap().age);

    
    assert_eq!(30, class.take_teacher().unwrap().age);
    assert!(class.teacher().is_none())
}


use std::rc::Rc;
use std::cell::{RefCell, RefMut};

//Object.as_ref_member();
//no lifetime for it
struct Object {
    s : String
}
impl Default for Object {
    fn default() -> Self{
        Object {s: "object".to_string()}
    }
}
impl Object {
    fn new(s: &str) -> Self {
        Object {s: s.to_string()}
    }
    fn as_ref(&self) -> &String {
        &(self.s)
    }
}

fn member_ref(){
    let o = Object::new("hello");
    println!("member_ref is :{}", o.as_ref());
    assert_eq!("hello", o.s);
}

// Rc::RefCell -> no option for it
fn refcell_take(){
    let ro: Rc<RefCell<Object>> = Rc::new(RefCell::new(Object::new("hello")));

    assert_eq!("hello", ro.borrow().as_ref());
    ro.take().as_ref();
    assert_eq!("object", ro.borrow().as_ref());
}


fn test_refcell_return_refmut(){
    fn b_mut(v: & RefCell<(u32, char)>) -> RefMut<(u32, char)> {
        v.borrow_mut()
    }
    let v = RefCell::new((5, 'b'));
    {
        let b1: RefMut<(u32, char)> = b_mut(&v);

        assert_eq!((5u32, 'b'), *b1);

        let mut b2: RefMut<u32> = RefMut::map(b1, |t| &mut t.0);
        *b2 = 20;
        *b2 = 10;
    }

    assert_eq!((10u32, 'b'), *(v.borrow_mut()));
}

pub fn main(){
    base();
    cell();

    member_ref();
    refcell_take();

    test_refcell_return_refmut();
}


